package de.h_da.fbi.cg.pointcloud.run;

import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;

import org.anddev.progressmonitor.ProgressMonitor;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;

import de.h_da.fbi.cg.pointcloud.adt.Graph;
import de.h_da.fbi.cg.pointcloud.adt.GraphEdgeMesh;
import de.h_da.fbi.cg.pointcloud.adt.GraphVertexMesh;
import de.h_da.fbi.cg.pointcloud.adt.VertexList;
import de.h_da.fbi.cg.pointcloud.emst.BoruvkaEuclideanMinimumSpanningTreeAlgorithm;
import de.h_da.fbi.cg.pointcloud.leaf.LeafPointConnector;
import de.h_da.fbi.cg.pointcloud.ui.dialog.ProgressDialog;
import de.h_da.fbi.cg.pointcloud.util.GraphUtil;
import de.h_da.fbi.cg.pointcloud.util.constants.Constants;

/**
 * @author Nicolas Gramlich
 * @since 15:49:47 - 11.11.2010
 */
public abstract class BaseApplication extends SimpleApplication {
	// ===========================================================
	// Constants
	// ===========================================================

	// ===========================================================
	// Fields
	// ===========================================================

	private Material mSolidColorMaterial;
	private float mRotation;
	protected boolean mRotate;

	// ===========================================================
	// Constructors
	// ===========================================================

	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	protected abstract VertexList getVertexList(final ProgressDialog progressDialog, final ProgressMonitor mainProgressMonitor) throws IOException;

	protected abstract Vector3f getStepTranslation();

	@Override
	public void simpleInitApp() {
		this.mSolidColorMaterial = new Material(BaseApplication.this.assetManager, "Common/MatDefs/Misc/SolidColor.j3md");

		this.cam.getLocation().y = 0.1f;
		this.cam.getLocation().z = 0.5f;
		this.cam.setFrustumPerspective(45f, (float) this.cam.getWidth() / this.cam.getHeight(), 0.01f, 1000f);

		final ProgressDialog progressDialog = new ProgressDialog(null);
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					final ProgressMonitor mainProgressMonitor = new ProgressMonitor(progressDialog);

					final VertexList vertices = getVertexList(progressDialog, mainProgressMonitor);

					/* SDG 0 */
					final Graph sdg0 = new Graph();
					sdg0.addVertices(vertices);

					final Geometry vertexGeometry = new Geometry("SDG0 (Vertices)", new GraphVertexMesh(sdg0));
					vertexGeometry.setMaterial(BaseApplication.this.getSolidColorMaterial(0, 1.0f, 1.0f));
					BaseApplication.this.rootNode.attachChild(vertexGeometry);


					/* SDG 1 */
					final ArrayList<Graph> emstComponents = GraphUtil.createComponentsWithNearestNeighborEdges(vertices, Constants.EMST_NEIGHBOR_COUNT);
					final ArrayList<Graph> sdg1s = new BoruvkaEuclideanMinimumSpanningTreeAlgorithm().computeEuclideanMinimumSpanningTree(emstComponents);

					for(int i = 0; i < sdg1s.size(); i++) {
						final Graph sdg1 = sdg1s.get(i);
						final float saturation = (i == 0) ? 1.0f : 0.25f;
						
						final Geometry emstGeometry = new Geometry("SDG1 (EMST) [" + i + "]", new GraphEdgeMesh(sdg1));
						emstGeometry.setMaterial(BaseApplication.this.getSolidColorMaterial(0.5f, saturation, saturation));
						emstGeometry.getLocalTransform().setTranslation(getStepTranslation());
						BaseApplication.this.rootNode.attachChild(emstGeometry);

						/* SDG 2 */
						final Graph sdg2 = new LeafPointConnector().compute(sdg1);
	
						final Geometry connectedLeafGeometry = new Geometry("SDG2 (ConnectedLeafs) [" + i + "]", new GraphEdgeMesh(sdg2));
						connectedLeafGeometry.setMaterial(BaseApplication.this.getSolidColorMaterial(0.75f, saturation, saturation));
						connectedLeafGeometry.getLocalTransform().setTranslation(getStepTranslation().mult(2));
						BaseApplication.this.rootNode.attachChild(connectedLeafGeometry);
					}

					progressDialog.dispose();
				} catch (final Exception e) {
					e.printStackTrace();
				}
			}
		}).start();

		this.inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE));

		this.inputManager.addListener(new ActionListener() {
			@Override
			public void onAction(final String pName, final boolean pIsPressed, final float pTpf) {
				BaseApplication.this.mRotate = pIsPressed;
			}
		}, new String[] { "Rotate"});

	}

	@Override
	public void simpleUpdate(final float pSecondsElapsed) {
		if(this.mRotate){
			this.mRotation += pSecondsElapsed;
			this.rootNode.setLocalRotation(this.rootNode.getLocalRotation().fromAngles(0, this.mRotation / FastMath.HALF_PI, 0));
		}
	}

	@Override
	public void simpleRender(final RenderManager pRenderManager) {

	}

	// ===========================================================
	// Methods
	// ==========================================================

	private Material getSolidColorMaterial(final float pHue, final float pSaturation, final float pValue) {
		final Material solidColorMaterial = BaseApplication.this.mSolidColorMaterial.clone();

		final Color color = new Color(Color.HSBtoRGB(pHue, pSaturation, pValue));
		solidColorMaterial.setColor("m_Color", new ColorRGBA(color.getRed() / 255.0f, color.getGreen() / 255.0f, color.getBlue() / 255.0f, 0.5f));

		return solidColorMaterial;
	}

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}
